<template>
  <div class="main">
    <div class="box">
      <grid-layout
        :layout.sync="layout"
        :col-num="colNum"
        :row-height="rowHeight"
        :is-draggable="true"
        :is-resizable="true"
        :margin="[10, 10]"
        :preventCollision="preventCollision"
        :responsive="false"
        :vertical-compact="false"
        :use-css-transforms="true"
      >
        <!-- 背景格子 -->
        <grid-item
          v-for="item in copy"
          :x="item.x"
          :y="item.y"
          :w="item.w"
          :h="item.h"
          :i="item.i"
          :key="item.i"
          :is-draggable="false"
          :is-resizable="false"
          class="gridItembox"
        />

        <!-- 允许拖动与忽略拖动元素 -->
        <!-- <grid-item
        v-for="item in layout"
        :x="item.x"
        :y="item.y"
        :w="item.w"
        :h="item.h"
        :i="item.i"
        :key="item.i"
        @move="moveEvent"
        @moved="movedEvent"
        @resize="resizeEvent"
        @resized="resizedEvent"
        class="gridItem"
        :style="{ backgroundColor: item.i === '0' ? '' : 'pink' }"
        drag-ignore-from=".gridBox"
        drag-allow-from=".draggable"
      >
        <div class="gridBox">不允许拖动</div>
        <div class="draggable"></div>
      </grid-item> -->
        <!-- 实际拖动元素 -->

        <grid-item
          v-for="item in layout"
          :x="item.x"
          :y="item.y"
          :w="item.w"
          :h="item.h"
          :i="item.i"
          :key="item.i"
          @move="moveEvent"
          @moved="movedEvent"
          @resize="resizeEvent"
          @resized="resizedEvent"
          class="gridItem"
          :style="{ backgroundColor: item.i === '0' ? '' : 'pink' }"
        >
          <div class="gridBox">{{ item.i }}</div>
          <div class="draggable" @click="dele(item.i)">&times;</div>
        </grid-item>

        <!-- 预览实现 -->
        <grid-item
          v-for="item in previewData"
          :x="item.x"
          :y="item.y"
          :w="item.w"
          :h="item.h"
          :i="item.i"
          :key="item.i"
          :is-draggable="false"
          :is-resizable="false"
          class="gridItemboxPreview"
        />
      </grid-layout>
    </div>
    <hr />
    <div
      @drag="drag"
      @dragend="dragend"
      class="droppable"
      draggable="true"
      unselectable="on"
    >
      (Drag me!)
    </div>
    <button @click="add">add</button>
  </div>
</template>

  
<script>
import { GridLayout, GridItem } from "vue-grid-layout";

export default {
  name: "layout",

  components: {
    GridLayout,
    GridItem,
  },
  data() {
    return {
      // 定义栅格系统列数
      layout: [
        {
          x: 0,
          y: 0,
          w: 1,
          h: 1,
          i: "0",
        },
        // { x: 1, y: 0, w: 1, h: 1, i: "1" },
      ],
      copy: [
        { x: 0, y: 0, w: 1, h: 1, i: "1" },
        { x: 0, y: 1, w: 1, h: 1, i: "2" },
        { x: 0, y: 2, w: 1, h: 1, i: "3" },
        { x: 0, y: 3, w: 1, h: 1, i: "4" },
        { x: 1, y: 0, w: 1, h: 1, i: "11" },
        { x: 1, y: 1, w: 1, h: 1, i: "12" },
        { x: 1, y: 2, w: 1, h: 1, i: "13" },
        { x: 1, y: 3, w: 1, h: 1, i: "14" },
        { x: 2, y: 0, w: 1, h: 1, i: "21" },
        { x: 2, y: 1, w: 1, h: 1, i: "22" },
        { x: 2, y: 2, w: 1, h: 1, i: "23" },
        { x: 2, y: 3, w: 1, h: 1, i: "24" },
      ],
      map: [],
      previewData: [],
      colNum: 3,
      rowHeight: 100,
      preventCollision: true,
    };
  },

  methods: {
    drag({ x, y }) {
      this.previewData = [];
      // console.log(e);
      const ex = x;
      const ey = y;
      // 当前坐标 340 160
      console.log("当前坐标", ex, ey);
      const gx = Math.ceil(ex / 280);
      const gy = Math.ceil(ey / 112);
      console.log("所在格子数", "列", gx, "行", gy);
      // 动态添加元素
      this.previewData.push({
        x: gx - 1,
        y: gy - 1,
        w: 1,
        h: 1,
        i: `item(x:${ex},y:${ey})`,
      });
    },
    dragend({ x, y }) {
      // 1. 获取当前坐标
      const ex = x;
      const ey = y;
      // 当前坐标 340 160
      console.log("当前坐标", ex, ey);
      const gx = Math.ceil(ex / 280);
      const gy = Math.ceil(ey / 112);
      console.log("所在格子数", "列", gx, "行", gy);
      // 动态添加元素
      this.layout.push({
        x: gx - 1,
        y: gy - 1,
        w: 1,
        h: 1,
        i: `item(x:${ex},y:${ey})`,
      });
    },
    add() {
      this.layout.push({
        x: 1,
        y: 2, // puts it at the bottom
        w: 1,
        h: 1,
        i: this.layout.length + 100,
      });
    },
    dele(i) {
      this.layout.splice(
        this.layout.findIndex((item) => item.i === i),
        1
      );
    },
    // 涉及多处的深拷贝
    deepClone(i) {
      return JSON.parse(JSON.stringify(i));
    },
    moveEvent(i, x, y) {
      console.log("移动中--move", i, x, y);
      //   1 根据移动位置，循环数据源当前位置是否有元素,不包含自己的位置
      const finditem = this.map.find(
        (item) => item.x === x && item.y === y && item.i != i
      );
      if (!finditem) return;
      console.log("找到了", finditem);
      this.changePosition(
        this.layout.find((item) => item.i === i),
        finditem
      );
    },
    // 同步数据
    saveData() {
      this.map = [];
      // 实现交换后，及时同步 数据映射
      this.map = this.deepClone(this.layout);
    },
    movedEvent() {
      this.saveData();
    },

    // 交换位置：
    changePosition(item1, item2) {
      console.log(item1, item2);
      // 取数据映射数据
      const item1Map = this.map.find((item) => item.i === item1.i);
      const item2Map = this.map.find((item) => item.i === item2.i);
      // 定义中间变量交换
      const temp = this.deepClone(item1Map);
      //   注意：修改的是影响显示的实际数组 layout
      this.layout.forEach((item) => {
        // 找到 item1,将 item1 的信息换成item2
        if (item.i === item1Map.i) {
          item.x = item2Map.x;
          item.y = item2Map.y;
        }
        if (item.i === item2Map.i) {
          item.x = temp.x;
          item.y = temp.y;
        }
      });

      this.saveData();
    },
    resizeEvent() {
      console.log("resize");
    },
    resizedEvent() {
      console.log("resized");
    },
  },

  mounted() {
    this.map = this.deepClone(this.layout);
  },
};
</script>

  
<style lang="less" scoped>
.droppable {
  border: solid #ccc px;
  width: 100px;
  height: 100px;
  background-color: #cccccc;
  color: red;
  cursor: move;
}
.box {
  overflow: hidden;
  border: solid red 1px;
  //   width: 500px;
  height: 500px;
  background-color: #031f2d;

  .gridItem {
    position: relative;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    border: solid #fff 1px;
    background-color: #cccccc;

    .draggable {
      position: absolute;
      right: 0;
      top: 0;
      width: 10px;
      height: 10px;
      // background-color: #000;
      border-radius: 10px;
      cursor: pointer;
    }
  }
  .gridItembox {
    border: dashed #fff 1px;
  }
  .gridItemboxPreview {
    background-color: rgba(0, 128, 0, 0.6);
  }
}
</style>
